package com.hui.auth.web;

import com.hui.auth.config.shiro.SecurityUtil;
import com.hui.auth.dto.JsonResult;
import com.hui.auth.entity.AuthUser;
import com.hui.auth.service.AuthUserService;
import com.hui.auth.service.OnlineService;
import com.hui.utils.DateUtil;
import com.hui.operatelog.OperateType;
import com.hui.operatelog.OperationLog;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;

/**
 * 登录管理控制器
 *
 * @author 廖云辉
 */
@Api(tags = "登录管理")
@RestController
@RequestMapping(value = "auth")
public class LoginController {
    @Autowired
    private OnlineService onlineService;
    @Autowired
    private AuthUserService userService;

    /**
     * 登录处理
     *
     * @return
     */
    @OperationLog(operation = OperateType.LOGIN, content = "")
    @ApiOperation(value = "登录")
    @RequestMapping(value = "login", method = RequestMethod.POST)
    public JsonResult loginUser(HttpServletRequest request, @RequestParam String username, @RequestParam String password) {
        JsonResult jsonResult = new JsonResult();
        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(username, password);
        Subject subject = SecurityUtils.getSubject();
        subject.login(usernamePasswordToken);//完成登录
        AuthUser user = SecurityUtil.currentUser();
        AuthUser userToDB = new AuthUser();
        userToDB.setId(user.getId());
        userToDB.setLastLogin(DateUtil.parseDateToString(new Date()));//最后一次登录时间
        userService.update(userToDB);
        jsonResult.setData(user);
        jsonResult.setMsg("登录成功");
        /*使用shiro自带的FormAuth可以不用实现自己的登录逻辑（此方法不处理登录成功,由shiro进行处理）*/
//        // 登录失败从request中获取shiro处理的异常信息
//        String exception = (String) request.getAttribute("shiroLoginFailure");
//        if (exception != null) {
//            if (UnknownAccountException.class.getName().equals(exception)) {
//                jsonResult.setMsg(AuthError.TOKEN_AUTH_ERROR.msg);
//                jsonResult.setCode(AuthError.TOKEN_AUTH_ERROR.code);
//            } else if (IncorrectCredentialsException.class.getName().equals(exception)) {
//                jsonResult.setMsg(AuthError.TOKEN_AUTH_ERROR.msg);
//                jsonResult.setCode(AuthError.TOKEN_AUTH_ERROR.code);
//            } else {
//                System.out.println(exception);
//                jsonResult.setMsg(exception);
//                jsonResult.setCode(AuthError.TOKEN_AUTH_ERROR.code);
//            }
//        }
//
//        jsonResult.setData(SecurityUtils.getSubject().getPrincipal());
//        jsonResult.setMsg("登录成功");
        return jsonResult;
    }

    /**
     * 注销
     *
     * @return
     */
    @ApiOperation(value = "注销")
    @RequestMapping(value = "login_out", method = RequestMethod.POST)
    public JsonResult loginOut() {
        JsonResult jsonResult = new JsonResult();
        SecurityUtils.getSubject().logout();
        jsonResult.setMsg("登出成功");
        return jsonResult;
    }


    /**
     * 当前已登录用户
     *
     * @return
     */
    @ApiOperation(value = "当前已登录用户")
    @RequestMapping(value = "select_online", method = RequestMethod.GET)
    public JsonResult selectOnline() {
        JsonResult<List<Map>> jsonResult = new JsonResult<List<Map>>();
        jsonResult.setData(onlineService.selectOnline());
        return jsonResult;
    }


    /**
     * 异步可以提高服务器的吞吐量
     */
    @ApiOperation(value = "当前已登录用户")
    @RequestMapping(value = "test_callable", method = RequestMethod.GET)
    public Callable<JsonResult> testCallable() throws InterruptedException {
        System.out.println("/test_callable被调用 thread id is : " + Thread.currentThread().getId());
        //此时处理线程处理其它请求，不用等待Callable线程返回结果
        return () -> {
            Thread.sleep(3000);
            System.out.println("Callable被调用 thread id is : " + Thread.currentThread().getId());
            return new JsonResult();
        };
    }
}
